home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / pctv3n2.zip / RTCHDW.C < prev    next >
C/C++ Source or Header  |  1992-04-16  |  8KB  |  233 lines

  1. #pragma inline
  2. #pragma option -1                 /* generate 286 instructions */
  3. /* RTCHDW.C -- AT Real-Time Clock control functions
  4.  * Author Jim Mischel.  Last update 03/22/92 */
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include "rtc.h"
  8.  
  9. /* Loop until "Update in Progress" bit is clear */
  10. static void WaitForUpdate (void) {
  11.     while (ReadCMOS (SRA) & UIP)
  12.     ;
  13. }
  14.  
  15. /* Read Value from CMOS RAM */
  16. int ReadCMOS (int Addr) {
  17.     int ch;
  18.     asm pushf                           /* save interrupt flag */
  19.     disable ();
  20.     if (Addr < SRA) WaitForUpdate ();
  21.     outportb (CMOS_Control, Addr);
  22.     ch = inportb (CMOS_Data);
  23.     asm popf                         /* restore interrupt flag */
  24.     return ch;
  25. } /* ReadCMOS */
  26.  
  27. /* Write Value to CMOS RAM */
  28. void WriteCMOS (int Addr, int Value) {
  29.     asm pushf                           /* save interrupt flag */
  30.     disable ();
  31.     if (Addr < SRA) WaitForUpdate ();
  32.     outportb (CMOS_Control, Addr);
  33.     outportb (CMOS_Data, Value);
  34.     asm popf                         /* restore interrupt flag */
  35. } /* WriteCMOS */
  36.  
  37. /* Compute and store new CMOS checksum */
  38. void NewCMOSChecksum (void) {
  39.     int Loc, CheckSum = 0;
  40.     for (Loc = 0x10; Loc < 0x2E; Loc++)
  41.     CheckSum += ReadCMOS (Loc);
  42.     WriteCMOS (0x2E, (CheckSum >> 8));
  43.     WriteCMOS (0x2F, (CheckSum & 0xFF));
  44. }
  45.  
  46. /* ISR pointers initially point to DummyIsr in case an
  47.  * interrupt is enabled for which no ISR has been installed. */
  48. static void far DummyIsr (void) {
  49. }
  50.  
  51. static void far (*PeriodicIsr) (void) = DummyIsr;
  52. static void far (*UpdateIsr) (void) = DummyIsr;
  53. static void far (*AlarmIsr) (void) = DummyIsr;
  54.  
  55. /* Setup periodic interrupt frequency and ISR */
  56. int SetPeriodicInt (int Freq, void far (*isr)()) {
  57.     if (ReadCMOS (SRB) & PIE)
  58.     return 1;                 /* can't set -- already enabled */
  59.     if (isr != NULL) PeriodicIsr = isr;
  60.     /* set new periodic rate */
  61.     WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | (Freq & 0x0f));
  62.     return 0;
  63. }
  64.  
  65. /* Setup update-ended ISR */
  66. int SetUpdateInt (void far (*isr)()) {
  67.     if (ReadCMOS (SRB) & UIE)
  68.     return 1;                 /* can't set -- already enabled */
  69.     if (isr != NULL) UpdateIsr = isr;
  70.     return 0;
  71. }
  72.  
  73. /* Convert binary value (0-99) to BCD */
  74. static int BinToBCD (int Bin) {
  75.     return ((Bin / 10) << 4) + (Bin % 10);
  76. }
  77.  
  78. /* Setup alarm time and ISR */
  79. int SetAlarmInt (struct RTCTIME *Time, void far (*isr)()) {
  80.     unsigned char srb;
  81.     if (ReadCMOS (SRB) & AIE)
  82.        return 1;              /* already set, exit with error */
  83.     if (isr != NULL) AlarmIsr = isr;
  84.     srb = ReadCMOS (SRB);
  85.     WriteCMOS (SRB, srb | 0x80);            /* turn on SET bit */
  86.     WriteCMOS (0x05, (Time->Hour < 0xc0) ?
  87.                  BinToBCD (Time->Hour) : Time->Hour);
  88.     WriteCMOS (0x03, (Time->Min < 0xc0) ?
  89.                  BinToBCD (Time->Min) : Time->Min);
  90.     WriteCMOS (0x01, (Time->Sec < 0xc0) ?
  91.                  BinToBCD (Time->Sec) : Time->Sec);
  92.     WriteCMOS (SRB, srb);                   /* restore SET bit */
  93.     return 0;
  94. }
  95.  
  96. /* Enable individual RTC interrupts */
  97. void EnableRTCint (int Which) {
  98.     WriteCMOS (SRB, (ReadCMOS (SRB) |
  99.             (Which & (UF | PF | AF))));
  100. }
  101.  
  102. /* Disable individual RTC interrupts */
  103. void DisableRTCint (int Which) {
  104.     WriteCMOS (SRB, (ReadCMOS (SRB) &
  105.             ~(Which & (UF | PF | AF))));
  106. }
  107.  
  108. /* Reset individual RTC interrupts and ISRs */
  109. void ResetRTCint (int Which) {
  110.     DisableRTCint (Which);
  111.     if (Which & PIE) {
  112.     PeriodicIsr = DummyIsr;
  113.   /* reset rate to 1024 ticks/sec */
  114.     WriteCMOS (SRA, (ReadCMOS (SRA) & 0xf0) | 6);
  115.     }
  116.     if (Which & UIE) UpdateIsr = DummyIsr;
  117.     if (Which & AIE) AlarmIsr = DummyIsr;
  118. }
  119.  
  120. static void far NewRTCint (void);             /* ISR Prototype */
  121. static void interrupt (*OldRTCint) () = NULL;   /* Old RTC ISR */
  122.  
  123. /* Pointer to new RTC ISR */
  124. static void interrupt (*RTCintPtr) () =
  125.         (void interrupt *)NewRTCint;
  126.  
  127. /* Enable the RTC interrupt */
  128. void TimerOn (void) {
  129.     disable ();
  130.     if (OldRTCint == NULL) {        /* save old RTC int vector */
  131.     OldRTCint = getvect (RTCINT);
  132.     setvect (RTCINT, RTCintPtr);
  133.     }
  134.     ReadCMOS (SRC);         /* clear pending RTC interrupts... */
  135.                           /* ...and enable RTC interrupt */
  136.     outportb (PIC2ctrl, inportb (PIC2ctrl) & 0xfe);
  137.     enable ();
  138. }
  139.  
  140. /* Disable RTC hardware interrupt */
  141. void TimerOff (void) {
  142.     disable ();
  143.   /* disable RTC interrupt */
  144.     outportb (PIC2ctrl, inportb (PIC2ctrl) | 1);
  145.     setvect (RTCINT, OldRTCint);              /* reset RTC ISR */
  146.     OldRTCint = NULL;
  147.     enable ();
  148. }
  149.  
  150. /* New INT 70H ISR.  Because the state of the stack is unknown
  151.  * when this function is entered, we must create a new stack
  152.  * before doing any processing.  As a result there can be no
  153.  * automatic (i.e. stack) variables defined within this function. */
  154. /* Define stack size and number of stacks */
  155. #define StackSize 128
  156. #define Stacks 3
  157. #define SaveRecordSize 8
  158. static char NewStack[StackSize*Stacks];
  159.  
  160. static unsigned char IntFlags;
  161.  
  162. static void far NewRTCint (void) {
  163.   /* save caller's context and setup new stack */
  164.     asm xchg bp,[word ptr cs:SaveArea]  /* get next stack area */
  165.     asm cmp bp,Offset EndSaveArea               /* last stack? */
  166.     asm jc Around                                  /* nope, OK */
  167.     asm jmp StackError                      /* Stack overflow! */
  168. Around:
  169.     asm mov [word ptr cs:bp+2],sp                /* save stack */
  170.     asm mov [word ptr cs:bp+4],ss
  171.     asm mov sp,[word ptr cs:SaveArea]       /* get and save... */
  172.     asm mov [word ptr cs:bp+6],sp            /* ...original BP */
  173.     asm mov sp,[word ptr cs:bp]             /* Setup new SP... */
  174.     asm add bp,SaveRecordSize            /* ...and point to... */
  175.     asm mov [word ptr cs:SaveArea],bp     /* ...next save area */
  176.     asm mov bp,DGROUP
  177.     asm mov ss,bp                   /* SS = local data segment */
  178.     asm pusha                     /* save general registers... */
  179.     asm push es                 /* ...and segment registers... */
  180.     asm push ds                             /* ...on new stack */
  181.     asm mov ds,bp                                   /* ds = ss */
  182.  
  183.  
  184.   /* Determine which interrupts occurred */
  185.     IntFlags = ReadCMOS (SRC) & ReadCMOS (SRB);
  186.     enable ();                            /* interrupts OK now */
  187.   /* call appropriate interrupt routines */
  188.     if (IntFlags & PF) (*PeriodicIsr) ();
  189.     if (IntFlags & UF) (*UpdateIsr) ();
  190.     if (IntFlags & AF) (*AlarmIsr) ();
  191.     outportb (PIC2data, EOI);   /* Reset interrupt controllers */
  192.     outportb (PIC1data, EOI);
  193.  
  194.   /* restore caller's context and return */
  195.     disable ();
  196.     asm pop ds                 /* restore segment registers... */
  197.     asm pop es
  198.     asm popa                       /* ...and general registers */
  199.     asm mov bp,[word ptr cs:SaveArea]            /* Restore... */
  200.     asm sub bp,SaveRecordSize         /* ...save area pointer, */
  201.     asm mov [word ptr cs:SaveArea],bp
  202.     asm mov ss,[word ptr cs:bp+4]              /* ...stack,... */
  203.     asm mov sp,[word ptr cs:bp+2]
  204.     asm pop bp                                    /* ...and BP */
  205.     asm iret
  206.  
  207. /*
  208.  * Stack overflow handler.
  209.  * Display an error message and hang the system.
  210.  */
  211. StackError:
  212.     asm mov ax,cs
  213.     asm mov ds,ax
  214.     asm mov dx,offset OverflowMessage
  215.     asm mov ah,9
  216.     asm int 21h
  217. DeadLoop:                                 /* system hangs here */
  218.     asm jmp short DeadLoop
  219.       /*** Local data ***/
  220.     asm OverflowMessage = $
  221.     asm db 13,10,7,'RTC Stack overflow'
  222.     asm db 13,10,'System Halted$'
  223.     asm SaveArea = $
  224.     asm dw Offset SaveArea+2
  225.     asm dw Offset DGROUP:NewStack + (Stacks * StackSize)
  226.     asm dw 3 dup (?)
  227.     asm dw Offset DGROUP:NewStack + ((Stacks-1) * StackSize)
  228.     asm dw 3 dup (?)
  229.     asm dw Offset DGROUP:NewStack + ((Stacks-2) * StackSize)
  230.     asm dw 3 dup (?)
  231.     asm EndSaveArea = $
  232. }
  233.